#ifndef N1UNIT_H_2009_09_16
#define N1UNIT_H_2009_09_16

#include "N0Lib.h"

/*************************************************

void main()
{
    N1UNIT_RUN_TESTS;
    *** real main ***
}
                  
#ifdef N1UNIT

N1TEST(testFunction)
{

    N1RET_ERROR("Error message.");
    N1RET_ERROR(245);

    N1CHECK(a==b, "Error a!=b - its wrong!");  //condition should be true
    N1CHECK(d==v, 246);

    N1ASSERT(c1,c1,"Error message"); //c1 should be equal c2

    N1UnitPrintf("Log message: c1=%d, c2=%d", c1, c2);
     
    N1RET_OK;
}

#endif

*************************************************/

#ifdef N1UNIT

typedef void(*TTestFunction)();

#define N1Unit_Success         0
#define N1Unit_Exception  -1

struct N1UnitListItem {
  const char     *name;
  TTestFunction  func;
  N1UnitListItem *next;
  int            error;  //expected error code, 0-success, -1 exception
  bool           skip;   //skip this test
  bool           perf;   //performance function
  bool           manual; //manual test
};

char N1UnitAddFunction(N1UnitListItem *p);
char N1UnitAddFunction(TTestFunction* func, const char* funcName);

#define N1TEST_ERROR(func,err) \
   void func(); \
   N1UnitListItem N1UnitListItemFor_##func = { #func, &func, 0, err }; \
   char N1UnitAdder_##func = N1UnitAddFunction(&N1UnitListItemFor_##func); \
   void func()

#define N1TEST_SKIP(func) \
   void func(); \
   N1UnitListItem N1UnitListItemFor_##func = { #func, &func, 0, 0, true }; \
   char N1UnitAdder_##func = N1UnitAddFunction(&N1UnitListItemFor_##func); \
   void func()

#define N1TEST_MAN(func) \
   void func(); \
   N1UnitListItem N1UnitListItemFor_##func = { #func, &func, 0, 0, false, false, true }; \
   char N1UnitAdder_##func = N1UnitAddFunction(&N1UnitListItemFor_##func); \
   void func()

#define N1TEST_PERF(func) \
   void func(); \
   N1UnitListItem N1UnitListItemFor_##func = { #func, &func, 0, 0, false, true }; \
   char N1UnitAdder_##func = N1UnitAddFunction(&N1UnitListItemFor_##func); \
   void func()

#define N1TEST_EXCEPTION(func) N1TEST_ERROR(func,N1Unit_Exception)

class N1UnitError
{
public:
    pcstr m_sError;
    int   m_nError;
    
    N1UnitError(int error) : m_sError(NULL), m_nError(error) {  };
    N1UnitError(pcstr error) : m_sError(error), m_nError(0) {  };
};

#define N1TEST(func) N1TEST_ERROR(func,N1Unit_Success)
#define N1TEST_OK(func) N1TEST(func)


/*  Return methods  */

#define N1RET_OK              return
#define N1RET_ERROR(error)    throw N1UnitError(error);

#define N1CHECK(cond,error)   if (!(cond)) throw N1UnitError(error);

uint32 N1UnitRunTests(uint32 count, const char* mask);

#define N1UNIT_RUN_TESTS N1UnitRunTests((argc>1)?atoi(argv[1]):1, NULL)
#define N1UNIT_RUN_TESTS_BY_MASK(tests) N1UnitRunTests((argc>1)?atoi(argv[1]):1, #tests)
   
#else //N1UNIT

#define N1TEST(func) \
   void func()

#define N1UNIT_RUN_TESTS

#endif //N1UNIT

#endif //N1UNIT_H_2009_09_16
